package com.lebang.medicalInquiry.controller;

import com.alibaba.fastjson.JSONObject;

import com.lebang.medicalInquiry.component.RedisComponent;
import com.lebang.medicalInquiry.constant.ConfigEnum;
import com.lebang.medicalInquiry.constant.RedisKeyEnum;
import com.lebang.medicalInquiry.constant.ResponseEnum;
import com.lebang.medicalInquiry.constant.annotation.RateLimit;
import com.lebang.medicalInquiry.constant.annotation.Require;
import com.lebang.medicalInquiry.exception.BusinessException;
import com.lebang.medicalInquiry.handler.LiveMessageHandler;
import com.lebang.medicalInquiry.model.chat.*;
import com.lebang.medicalInquiry.model.po.OffLineNotice;
import com.lebang.medicalInquiry.model.po.User;
import com.lebang.medicalInquiry.model.vo.PageVo;
import com.lebang.medicalInquiry.model.vo.UserInfoVo;
import com.lebang.medicalInquiry.response.Callback;
import com.lebang.medicalInquiry.response.JsonData;
import com.lebang.medicalInquiry.service.ConfigService;
import com.lebang.medicalInquiry.service.UserService;
import com.lebang.medicalInquiry.utils.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;

import okhttp3.*;
import okhttp3.RequestBody;
import okhttp3.sse.EventSource;
import okhttp3.sse.EventSources;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 根据gpt实现聊天 或者根据gpt解析指令并且返回
 */
@Slf4j
@RestController
@Api("gpt")
@RequestMapping("/api/open")
public class OpenApi {

    @Autowired
    private RedisComponent redisComponent;

    @Autowired
    private ConfigService configService;

    @Autowired
    private LiveMessageHandler messageHandler;

    @Autowired
    private UserService userService;

    @Value("${azure.key}")
    private String azureKey;

    @RateLimit(key = "gpt_ask:", capacity = 6, requestedTokens = 2)
    @PostMapping(value = "/chat", produces = "text/event-stream")
    public ResponseEntity<SseEmitter> chat(
            @ApiParam(name = "问题", value = "question") @RequestParam(value = "question", required = false) String content,
            @ApiParam(name = "图片路劲", value = "imgUrl") @RequestParam(value = "imgUrl", required = false) String imgUrl) {
        SseEmitter sseEmitter = new SseEmitter();

        String byCode = configService.getByCode(ConfigEnum.gpt.getConfigType());
        JSONObject gptJson = JSONObject.parseObject(byCode);
        String comm = !TextUtil.isEmpty(content) ? gptJson.getString("gptAsk") : gptJson.getString("gptFileAsk");
        String key = UUID.randomUUID().toString().replace("-", "");
        if (!TextUtil.isEmpty(imgUrl)) {
            int times = 0;
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("key", key);
            jsonObject.put("imgUrl", imgUrl);
            redisComponent.leftPush(RedisKeyEnum.gpt_file_parse.getName(), jsonObject);
            while (times <= 10) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                Object value = redisComponent.getValue(RedisKeyEnum.gpt_file_ask.getName() + key);
                if (!TextUtil.isEmpty(value)) {
                    content = value.toString();
                    break;
                }
                times++;

            }
        }
        if (TextUtil.isEmpty(content)) {
            sseEmitter.complete();
            throw new BusinessException("内容为空,解析失败");
        }
        Message message = Message.ofSystem(comm + content);
        List<Message> messages = new ArrayList<>();
        messages.add(message);
        OkHttpClient instance = OkhttpClientUtils.getInstance();
        ChatRequest requestBody = ChatRequest.builder().messages(messages)
                .frequencyPenalty(0)
                .maxTokens(2048)
                .temperature(0.7)
                .frequencyPenalty(0)
                .presencePenalty(0)
                .topP(0.95)
                .stream(true)
                .build();

        Request build = new Request.Builder().get()
                .url("https://soundaichatgpt.openai.azure.com/openai/deployments/xmlbgpt35turbo/chat/completions?api-version=2023-03-15-preview")
                .post(RequestBody.create(MediaType.parse("application/json"), JSONObject.toJSONString(requestBody)))
                .addHeader("api-key", azureKey)
                .build();

        EventSource.Factory factory = EventSources.createFactory(instance);

        SseStreamListener sseStreamListener = new SseStreamListener(sseEmitter);
        factory.newEventSource(build, sseStreamListener);
        //onComplate 接收一个Consumer( Java 中的一个函数式接口，它代表了一个接受单个参数并且没有返回值的操作)的函数式对象  通过调用accept 可以执行此函数对象实现的内容
        sseStreamListener.setOnComplate(msg -> {
            //回答完成，可以做一些事情
            System.out.println("消息内容:" + msg);
            // 需要手动关闭 否则会出现超时异常
            sseEmitter.complete();
        });
        return ResponseEntity.ok(sseEmitter);
    }


    @PostMapping("/qa/notice")
    @ApiOperation("通知当前回答的用户是那个")
    public JsonData<PageVo<List<OffLineNotice>>> qaNotice(HttpServletRequest request, HttpServletResponse response,
                                                          @ApiParam(name = "userId", value = "回答的uuid", required = true) @NotNull(message = "userId 不能为空")
                                                          @RequestParam(value = "userId", required = false) String userId,
                                                          @ApiParam(name = "question", value = "问题", required = true) @NotNull(message = "question 不能为空")
                                                          @RequestParam(value = "question", required = false) String question,
                                                          @ApiParam(name = "liveRoomId", value = "直播间id", required = true) @NotNull(message = "liveRoomId 不能为空")
                                                          @RequestParam(value = "liveRoomId", required = false) String liveRoomId,
                                                          @ApiParam(name = "status", value = "start:开始回答 end：结束回答")
                                                          @RequestParam(value = "status", required = false, defaultValue = "1") String status) {
        try {
            // rtmp 推流延迟
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("弹幕通知，问题:" + question + "_uuid:" + userId + "_status:" + status);
        UserInfoVo name = userService.getByUuid(userId);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("status", status);
        jsonObject.put("name", name.getName());
        jsonObject.put("headImg", name.getHeadImg());
        jsonObject.put("liveRoomId", liveRoomId);
        jsonObject.put("question", question);
        messageHandler.qaNotice(liveRoomId, jsonObject.toJSONString());

        return Callback.success(ResponseEnum.SUCCESS.getCode(), ResponseEnum.SUCCESS.getMemo());

    }


    @GetMapping("/live/callback")
    @ApiOperation("直播状态回调")
    public JsonData<PageVo<List<OffLineNotice>>> qaNotice(HttpServletRequest request, HttpServletResponse response,
                                                          @ApiParam(name = "action", value = "直播动作", required = true) @NotNull(message = "action 不能为空")
                                                          @RequestParam(value = "action", required = false) String action,
                                                          @ApiParam(name = "ip", value = "问题", required = true) @NotNull(message = "ip 不能为空")
                                                          @RequestParam(value = "ip", required = false) String ip,
                                                          @ApiParam(name = "id", value = "推流流名称", required = true) @NotNull(message = "id 不能为空")
                                                          @RequestParam(value = "id", required = false) String liveRoomId,
                                                          @ApiParam(name = "app", value = "推流域名")
                                                          @RequestParam(value = "app", required = false, defaultValue = "1") String app,
                                                          @ApiParam(name = "appname", value = "推流应用名称")
                                                          @RequestParam(value = "appname", required = false, defaultValue = "1") String appname,
                                                          @ApiParam(name = "time", value = "时间")
                                                          @RequestParam(value = "time", required = false, defaultValue = "1") String time) {

        if ("publish_done".equals(action)) {
            final boolean status = AuthLiveUrlUtil.getOnLineStreamStatus("LTAI5tMnge1S32zRbkifux32", "AaSfFM5k9NIxHK6vG3FLo63JWQGaDj", app, appname, liveRoomId);
            if (!status) {
                System.out.println("关播:" + liveRoomId);
//                    messageHandler.closeLive(liveRoomId);
            }
            //7481c37a61fbddf340de923ea5f8b2f0
            //http://pullstream.digitalmate.cn/live/7481c37a61fbddf340de923ea5f8b2f0.flv?auth_key=1705727628-0-0-1569824399e2cc842a62ab4b1ff0376e
            // rtmp 推流延迟

        }


        return Callback.success(ResponseEnum.SUCCESS.getCode(), ResponseEnum.SUCCESS.getMemo());

    }


//    @PostMapping(value = "/query", produces = "text/event-stream")
//    @ApiOperation("询问问题")
//    public ResponseEntity<SseEmitter> qaNotice(HttpServletRequest request, HttpServletResponse response,
//                                               @ApiParam(name = "questing", value = "问题", required = true) @NotNull(message = "questing 不能为空")
//                                               @RequestParam(value = "questing", required = false) String questing) {
//
//        SseEmitter sseEmitter = new SseEmitter();
//        int times = 0;
//        JSONObject jsonObject = new JSONObject();
//        jsonObject.put("questing", questing);
//        String key = UUID.randomUUID().toString().replace("-", "");
//        jsonObject.put("key", key);
//        redisComponent.leftPush(RedisKeyEnum.questing.getName(), jsonObject);
//        String content = "";
//        while (times <= 10) {
//            try {
//                Thread.sleep(500);
//            } catch (InterruptedException e) {
//                throw new RuntimeException(e);
//            }
//            Object value = redisComponent.getValue(RedisKeyEnum.questing_ask.getName() + key);
//            if (!TextUtil.isEmpty(value)) {
//                content = value.toString();
//                break;
//            }
//            times++;
//        }
//        if (!TextUtil.isEmpty(content)) {
//            for (int i = 0; i < content.length(); i++) {
//                final String substring = content.substring(i, content.length() > i + 1 ? i + 1 : content.length() - 1);
//                try {
//                    sseEmitter.send(substring);
//                } catch (IOException e) {
////            throw new RuntimeException(e);
//                }
//            }
//        }
//        sseEmitter.complete();
//        return ResponseEntity.ok(sseEmitter);
//
//    }

    @PostMapping(value = "/query")
    @ApiOperation("询问问题")
    public JsonData qaNotice(HttpServletRequest request, HttpServletResponse response,
                             @ApiParam(name = "questing", value = "问题", required = true) @NotNull(message = "questing 不能为空")
                             @RequestParam(value = "questing", required = false) String questing) {


        int times = 0;
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("questing", questing);
        String key = UUID.randomUUID().toString().replace("-", "");
        jsonObject.put("key", key);
        redisComponent.leftPush(RedisKeyEnum.questing.getName(), jsonObject);
        String content = "";
        while (times <= 10) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            Object value = redisComponent.getValue(RedisKeyEnum.questing_ask.getName() + key);
            if (!TextUtil.isEmpty(value)) {
                content = value.toString();
                break;
            }
            times++;
        }

        return Callback.success(ResponseEnum.SUCCESS.getCode(), ResponseEnum.SUCCESS.getMemo(), content);

    }

//    @PostMapping(value = "/gpt/parse")
//    public JsonData chatParse(
//            @RequestParam(name = "content") String question) {
//
//
//
//        Message system = Message.ofSystem("Don't make assumptions about what values to use with functions. Ask for clarification if a user request is ambiguous. and Only use the functions you have been provided with.");
//        Message message = Message.ofSystem(question);
//
//        List<Message> messages = new ArrayList<>();
//        messages.add(system);
//        messages.add(message);
//        OkHttpClient instance = OkhttpClientUtils.getInstance();
//
//        ChatRequest requestBody = ChatRequest.builder().messages(messages)
//                .frequencyPenalty(0)
//                .maxTokens(2048)
//                .temperature(0.7)
//                .frequencyPenalty(0)
//                .presencePenalty(0)
//                .topP(0.95)
//                .stream(false)
//                .build();
//        String s1 = JSONObject.toJSONString(requestBody);
//        Request build = new Request.Builder().get()
//                .url("https://soundaichatgpt.openai.azure.com/openai/deployments/xmlbgpt35turbo/chat/completions?api-version=2023-07-01-preview")
//                .post(RequestBody.create(MediaType.parse("application/json"), s1))
//                .addHeader("api-key", azureKey)
//                .build();
//        ChatRespone chatRespone = null;
//        JSONObject jsonObject = new JSONObject();
//        try {
//            Response execute = instance.newCall(build).execute();
//            String string = execute.body().string();
//            chatRespone = JSONObject.parseObject(string, ChatRespone.class);
//            log.info("gptRespone", chatRespone);
//            ChatRespone.Choices choices = chatRespone.getChoices().get(0);
//            String finishReason = choices.getFinishReason();
//            log.info("question：{},content{}", question, choices.getMessage());
//            if ("function_call".equals(finishReason)) {
//                String functionCall = choices.getMessage().getFunctionCall();
//                jsonObject = JSONObject.parseObject(functionCall);
//                JSONObject arguments = jsonObject.getJSONObject("arguments");
//                jsonObject.put("arguments", arguments);
//            } else {
//                String content = choices.getMessage().getContent();
//                jsonObject.put("name", "chat");
//                jsonObject.put("content", content);
//            }
//        } catch (IOException e) {
//            throw new RuntimeException(e);
//        }
////        String content = chatRespone.getChoices().get(0).getMessage().getContent();
////        try {
////            JSONObject jsonObject = JSONObject.parseObject(content);
////            System.out.println(jsonObject);
////        } catch (JSONException ex) {
////            JSONObject jsonObject = new JSONObject();
////            jsonObject.put("Action", "question");
////            jsonObject.put("Answer", content);
////            content = jsonObject.toJSONString();
////        }
//        return Callback.success(ResponseEnum.SUCCESS.getCode(), ResponseEnum.SUCCESS.getName(), jsonObject);
//
//    }


}


